https://thesobersobber.github.io/CP-Snippets/two-sat (kosaraju)
/**
* Given a set of clauses (a1 v a2)^(a2 v ¬a3)....
* this algorithm find a solution to it set of clauses.
* test: http://lightoj.com/volume_showproblem.php?problem=1251
**/
#include<bits/stdc++.h>
using namespace std;
#define MAX 100000
#define endl '
'
vector<int> G[MAX];
vector<int> GT[MAX];
vector<int> Ftime;
vector<vector<int> > SCC;
bool visited[MAX];
int n;
void dfs1(int n){
visited[n] = 1;
for (int i = 0; i < G[n].size(); ++i) {
int curr = G[n][i];
if (visited[curr]) continue;
dfs1(curr);
}
Ftime.push_back(n);
}
void dfs2(int n, vector<int> &scc) {
visited[n] = 1;
scc.push_back(n);
for (int i = 0;i < GT[n].size(); ++i) {
int curr = GT[n][i];
if (visited[curr]) continue;
dfs2(curr, scc);
}
}
void kosaraju() {
memset(visited, 0, sizeof visited);
for (int i = 0; i < 2 * n ; ++i) {
if (!visited[i]) dfs1(i);
}
memset(visited, 0, sizeof visited);
for (int i = Ftime.size() - 1; i >= 0; i--) {
if (visited[Ftime[i]]) continue;
vector<int> _scc;
dfs2(Ftime[i],_scc);
SCC.push_back(_scc);
}
}
/**
* After having the SCC, we must traverse each scc, if in one SCC are -b y b, there is not a solution.
* Otherwise we build a solution, making the first "node" that we find truth and its complement false.
**/
bool two_sat(vector<int> &val) {
kosaraju();
for (int i = 0; i < SCC.size(); ++i) {
vector<bool> tmpvisited(2 * n, false);
for (int j = 0; j < SCC[i].size(); ++j) {
if (tmpvisited[SCC[i][j] ^ 1]) return 0;
if (val[SCC[i][j]] != -1) continue;
else {
val[SCC[i][j]] = 0;
val[SCC[i][j] ^ 1] = 1;
}
tmpvisited[SCC[i][j]] = 1;
}
}
return 1;
}
// Example of use
int main() {
int m, u, v, nc = 0, t; cin >> t;
// n = "nodes" number, m = clauses number
while (t--) {
cin >> m >> n;
Ftime.clear();
SCC.clear();
for (int i = 0; i < 2 * n; ++i) {
G[i].clear();
GT[i].clear();
}
// (a1 v a2) = (¬a1 -> a2) = (¬a2 -> a1)
for (int i = 0; i < m ; ++i) {
cin >> u >> v;
int t1 = abs(u) - 1;
int t2 = abs(v) - 1;
int p = t1 * 2 + ((u < 0)? 1 : 0);
int q = t2 * 2 + ((v < 0)? 1 : 0);
G[p ^ 1].push_back(q);
G[q ^ 1].push_back(p);
GT[p].push_back(q ^ 1);
GT[q].push_back(p ^ 1);
}
vector<int> val(2 * n, -1);
cout << "Case " << ++nc <<": ";
if (two_sat(val)) {
cout << "Yes" << endl;
vector<int> sol;
for (int i = 0; i < 2 * n; ++i)
if (i % 2 == 0 and val[i] == 1)
sol.push_back(i / 2 + 1);
cout << sol.size() ;
for (int i = 0; i < sol.size(); ++i) {
cout << " " << sol[i];
}
cout << endl;
} else {
cout << "No" << endl;
}
}
return 0;
}